package com.userdemo.demo.util.elasticsearch;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import com.userdemo.demo.constant.base.Const;
import com.userdemo.demo.util.base.StringUtil;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.*;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * 　　* @description: TODO
 * 　　* @param ${tags}
 * 　　* @return ${return_type}
 * 　　* @throws
 * 　　* @author 陈宇
 * 　　* @date $date$ $time$
 *
 */
@Component
public class ElasticsearchUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(ElasticsearchUtil.class);

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    private static RestHighLevelClient client;

    private static ObjectMapper mapper = new ObjectMapper();

    /**
     * @PostContruct是spring框架的注解
     * spring容器初始化的时候执行该方法
     */
    @PostConstruct
    public void init() {
        client = this.restHighLevelClient;
    }

    /**
     * 创建索引
     *
     * @param index
     * @return
     */
    public static boolean createIndex(String index) {
        //index名必须全小写，否则报错
        CreateIndexRequest request = new CreateIndexRequest(index);
        try {
            CreateIndexResponse indexResponse = client.indices().create(request, RequestOptions.DEFAULT);
            if (indexResponse.isAcknowledged()) {
                LOGGER.info("创建索引成功");
            } else {
                LOGGER.info("创建索引失败");
            }
            return indexResponse.isAcknowledged();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return false;
    }

    /**
     * 插入数据
     * @param index
     * @param type
     * @param object
     * @return
     */
    public static String addData(String index,String type,String id,JSONObject object) {
        IndexRequest indexRequest = new IndexRequest(index, type, id);
        try {
            return index(indexRequest,object);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 插入数据
     * @param object
     * @return
     */
    public static String addData(String index,JSONObject object) {
        IndexRequest indexRequest = new IndexRequest(index);
        try {
            return index(indexRequest,object);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    static String index(IndexRequest indexRequest,JSONObject object){
        try {
            indexRequest.source(mapper.writeValueAsString(object), XContentType.JSON);
            IndexResponse indexResponse = client.index(indexRequest, RequestOptions.DEFAULT);
            return indexResponse.getId();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 检查索引
     * @param index
     * @return
     * @throws IOException
     */
    public static boolean checkIndexExist(String index) {
        try {
            Request request = new Request("HEAD", index);
            Response response = client.getLowLevelClient().performRequest(request);
            boolean exist = response.getStatusLine().getReasonPhrase().equals("OK");
            return exist;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }


    /**
     * 条件查询数据
     * @param index
     * @param type
     * @param map
     * @return
     */
    public static LinkedList<Map> selectByParamMap(String index, String type, Map<String, String> map){
        BoolQueryBuilder boolBuilder = QueryBuilders.boolQuery();
        Iterator<Map.Entry<String, String>> entries = map.entrySet().iterator();
        while (entries.hasNext()) {
            Map.Entry<String, String> entry = entries.next();
            if (StringUtil.isNotEmpty(entry.getKey()) && StringUtil.isNotEmpty(entry.getValue())) {
                boolBuilder.must(QueryBuilders.matchQuery(entry.getKey(), entry.getValue()));
            }
        }
        try {
            LinkedList<Map> linkedList = selectByMuchillegible(boolBuilder,index,type);
            /*if(null == linkedList || 30 > linkedList.size() ){
                //拆成每个条件查询
                entries = map.entrySet().iterator();
                while (entries.hasNext()) {
                    Map.Entry<String, String> entry = entries.next();
                    if (StringUtil.isNotEmpty(entry.getKey()) && StringUtil.isNotEmpty(entry.getValue())) {
                        boolBuilder = QueryBuilders.boolQuery();
                        boolBuilder.must(QueryBuilders.matchQuery(entry.getKey(), entry.getValue()));
                        linkedList.addAll(selectByMuchillegible(boolBuilder,index, type));
                    }
                }
                boolBuilder = null;
            }*/
            return linkedList;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * multi_match查询
     * @param boolBuilder
     * @return
     * @throws IOException
     */
    public static LinkedList<Map> selectByMuchillegible(BoolQueryBuilder boolBuilder,String index, String type) throws IOException {

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(boolBuilder);
        //sourceBuilder.from(0);
        //sourceBuilder.size(100); // 获取记录数，默认10
        //sourceBuilder.fetchSource(new String[] { "id", "name" }, new String[] {}); // 第一个是获取字段，第二个是过滤的字段，默认获取全部
        SearchRequest searchRequest = new SearchRequest(index);
        searchRequest.types(type);
        searchRequest.source(sourceBuilder);
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        SearchHit[] searchHits = hits.getHits();
        LinkedList<Map> resultList = Lists.newLinkedList();
        if(null != searchHits){
            for (SearchHit hit : searchHits) {
                if(StringUtil.isNotEmpty(hit.getSourceAsString())){
                    Map<String,String> resultMap = (Map)JSONObject.parse(hit.getSourceAsString());
                    if(null != resultMap){
                        resultList.add(resultMap);
                    }
                }

            }
        }
        return resultList;
    }

    /**
     * 获取低水平客户端
     * @return
     */
    public static RestClient getLowLevelClient() {
        return client.getLowLevelClient();
    }

    public static LinkedList match(Map<String,String> map,LinkedList<Map> linkedList){
        //进行相似度匹配，人工干预
        LinkedList resultList = Lists.newLinkedList();
        //产品名称
        String parProductName = map.get("productName");
        //生产厂家
        String parManufacturer = map.get("manufacturer");
        //型号，
        String parStandard = map.get("standard");
        //规格
        String parModel = map.get("model");
        for (int i = 0; i <linkedList.size() ; i++) {
            //产品名称
            String productName = StringUtil.valueOfString(linkedList.get(i).get("productName"));
            //注册证名称
            String regName = StringUtil.valueOfString(linkedList.get(i).get("regName"));
            //生产厂家
            String manufacturer = StringUtil.valueOfString(linkedList.get(i).get("manufacturer"));
            //厂家中文简称
            String chinaName = StringUtil.valueOfString(linkedList.get(i).get("chinaName"));
            //型号，
            String standard =  StringUtil.valueOfString(linkedList.get(i).get("standard"));
            //规格
            String model =  StringUtil.valueOfString(linkedList.get(i).get("model"));
            //如果产品名称匹配注册证，或产品名称匹配产品名称
            if((StringUtil.levenshtein(parProductName,productName) > 0.99 ||
                    StringUtil.levenshtein(parProductName,regName) > 0.99) &&
                    (StringUtil.levenshtein(parManufacturer,manufacturer) > 0.99
                            || StringUtil.levenshtein(parManufacturer,chinaName) > 0.99)) {
                //如果型号规格也匹配上最好
                if (StringUtil.levenshtein(parStandard, standard) > 0.3 ||
                        StringUtil.levenshtein(parStandard, model) > 0.3 ||
                        StringUtil.levenshtein(parModel, standard) > 0.3 ||
                        StringUtil.levenshtein(parModel, model) > 0.3) {
                    resultList.add(linkedList.get(i));
                    continue;
                } else {
                    resultList.add(linkedList.get(i));
                    continue;
                }
            }
            if((StringUtil.levenshtein(parProductName,productName) > 0.8 ||
                    StringUtil.levenshtein(parProductName,regName) > 0.8) &&
                    (StringUtil.levenshtein(parManufacturer,manufacturer) > 0.899
                            || StringUtil.levenshtein(parManufacturer,chinaName) > 0.8)) {
                //如果型号规格也匹配上最好
                if (StringUtil.levenshtein(parStandard, standard) > 0.3 ||
                        StringUtil.levenshtein(parStandard, model) > 0.3 ||
                        StringUtil.levenshtein(parModel, standard) > 0.3 ||
                        StringUtil.levenshtein(parModel, model) > 0.3) {
                    resultList.add(linkedList.get(i));
                    continue;
                } else {
                    resultList.add(linkedList.get(i));
                    continue;
                }
            }
            if((StringUtil.levenshtein(parProductName,productName) > 0.7 ||
                    StringUtil.levenshtein(parProductName,regName) > 0.7) &&
                    (StringUtil.levenshtein(parManufacturer,manufacturer) > 0.7
                            || StringUtil.levenshtein(parManufacturer,chinaName) > 0.7)) {
                //如果型号规格也匹配上最好
                if (StringUtil.levenshtein(parStandard, standard) > 0.3 ||
                        StringUtil.levenshtein(parStandard, model) > 0.3 ||
                        StringUtil.levenshtein(parModel, standard) > 0.3 ||
                        StringUtil.levenshtein(parModel, model) > 0.3) {
                    resultList.add(linkedList.get(i));
                    continue;
                } else {
                    resultList.add(linkedList.get(i));
                    continue;
                }
            }
        }
        return resultList;
    }


    /**
     * 批量删除索引内数据
     * @param list
     */
    public static void delData(List<Long> list){
        BulkRequest bulkRequest = new BulkRequest();
        for (Long id : list){
            DeleteRequest deleteRequest = new DeleteRequest(Const.BaseLogEsIndex.INDEXNAME,
                    Const.BaseLogEsIndex.TYPE,StringUtil.valueOfString(id));
            bulkRequest.add(deleteRequest);
        }
        try {
            client.bulk(bulkRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
